"""
@author: wangkang
@contact: wangkang@autobio.com.cn
@file: question_classifier.py
@time: 2020/3/27 18:40
@desc: 问句分类
"""
import os
import ahocorasick


class QuestionClassifier:
    def __init__(self):
        cur_dir = os.path.dirname(os.path.dirname(__file__))
        # 　特征词路径
        self.ins_type_path = os.path.join(cur_dir, 'data/设备类型.txt')
        self.unit_path = os.path.join(cur_dir, 'data/部位.txt')
        self.method_path = os.path.join(cur_dir, 'data/具体方法.txt')
        self.sub_unit_path = os.path.join(cur_dir, 'data/子部位.txt')
        self.process_path = os.path.join(cur_dir, 'data/处理方向.txt')
        self.apparance_path = os.path.join(cur_dir, 'data/具体表现.txt')
        self.deny_path = os.path.join(cur_dir, 'data/否定词.txt')
        # 加载特征词
        self.ins_type_wds = [i.strip() for i in open(self.ins_type_path, encoding='utf-8') if i.strip()]
        self.unit_wds = [i.strip() for i in open(self.unit_path, encoding='utf-8') if i.strip()]
        self.method_wds = [i.strip() for i in open(self.method_path, encoding='utf-8') if i.strip()]
        self.sub_unit_wds = [i.strip() for i in open(self.sub_unit_path, encoding='utf-8') if i.strip()]
        self.process_wds = [i.strip() for i in open(self.process_path, encoding='utf-8') if i.strip()]
        self.apparance_wds = [i.strip() for i in open(self.apparance_path, encoding='utf-8') if i.strip()]
        self.region_words = set(
            self.unit_wds + self.ins_type_wds + self.method_wds + self.sub_unit_wds + self.process_wds + self.apparance_wds)
        self.deny_words = [i.strip() for i in open(self.deny_path, encoding='utf-8') if i.strip()]

        # 构造领域actree
        self.region_tree = self.build_actree(list(self.region_words))
        # 构建词典
        self.wdtype_dict = self.build_wdtype_dict()

        # 问句疑问词
        self.apparance_qwds = ['哪些表征', '哪些现象', '哪些情况', '哪些状态', '哪些行为', '哪些表现', '哪些异常', '哪些不正常', '哪些不寻常', '哪些非正常', '哪些故障',
                               '什么表征', '什么现象', '什么情况', '什么状态', '什么行为', '什么表现', '什么异常', '什么不正常', '什么不寻常', '什么非正常', '什么故障',
                               '啥表征', '啥现象', '啥情况', '啥状态', '啥行为', '啥表现', '啥异常', '啥不正常', '啥不寻常', '啥非正常', '啥故障']
        self.cause_qwds = ['原因', '成因', '为什么', '怎么会', '怎样才', '咋样才', '怎样会', '如何会', '为啥', '为何', '如何才会', '怎么才会', '会导致', '会造成']
        self.method_qwds = ['怎么办', '怎么做', '怎么维修', '怎么保养', '怎么维护', '怎么解决', '保养', '维护', '处理',
                            '如何办', '如何保养', '如何做', '如何维修', '如何维护', '如何解决',
                            '咋办', '咋做', '咋维修', '咋维护', '咋解决', '咋保养']
        self.apply_qwds = ['用在', '用于', '有效', '有用', '应用', '使用']
        self.appear_on = ['出现在', '发生在', '在哪']
        self.have_qwds = ['有哪些', '由哪些', '有啥', '通过啥', '通过什么', '有什么', '由什么', '包括什么', '包括哪些', '包含什么', '包含哪些']
        self.belong_qwds = ['属于', '算']

        # print('model init finished ......')

        return

    def build_wdtype_dict(self):
        """
        构造词对应的类型'
        :return:
        """
        wd_dict = dict()
        for wd in self.region_words:
            wd_dict[wd] = []
            if wd in self.ins_type_wds:
                wd_dict[wd].append('INSTRUMENT')
            if wd in self.unit_wds:
                wd_dict[wd].append('UNIT')
            if wd in self.method_wds:
                wd_dict[wd].append('METHOD')
            if wd in self.sub_unit_wds:
                wd_dict[wd].append('SUB_UNIT')
            if wd in self.process_wds:
                wd_dict[wd].append('PROCESS')
            if wd in self.apparance_wds:
                wd_dict[wd].append('APPARANCE')
        return wd_dict

    def build_actree(self, wordlist):
        """
        构造actree，加速过滤
        :param wordlist:
        :return:
        """
        actree = ahocorasick.Automaton()
        for index, word in enumerate(wordlist):
            actree.add_word(word, (index, word))
        actree.make_automaton()
        return actree

    def method_medical(self, question):
        """
        问句过滤
        :param question:
        :return:
        """
        region_wds = []
        for i in self.region_tree.iter(question):
            wd = i[1][1]
            region_wds.append(wd)
        stop_wds = []
        for wd1 in region_wds:
            for wd2 in region_wds:
                if wd1 in wd2 and wd1 != wd2:
                    stop_wds.append(wd1)
        final_wds = [i for i in region_wds if i not in stop_wds]
        final_dict = {i: self.wdtype_dict.get(i) for i in final_wds}

        return final_dict

    def method_words(self, wds, sent):
        """
        基于问句疑问词进行问句分类
        :param wds: 问句疑问词列表
        :param sent: 问句
        :return: 问句中是都包含设定的疑问词
        """
        for wd in wds:
            if wd in sent:
                return True
        return False

    def classify(self, question):
        """
        问句分类主函数
        :param question: 问句
        :return: 哪类实体的哪种问句类型
        """
        data = {}
        # 过滤出实体属于6大类中的哪几类
        medical_dict = self.method_medical(question)
        if not medical_dict:
            return {}
        data['args'] = medical_dict
        # 收集问句当中所涉及到的实体类型
        types = []
        for type_ in medical_dict.values():
            types += type_
        question_type = 'others'

        question_types = []

        # 单元有哪些（异常）状态
        if self.method_words(self.apparance_qwds, question) and ('UNIT' in types):
            question_type = 'unit_apparance'
            question_types.append(question_type)

        # 某类型设备有哪些单元组成
        if self.method_words(self.have_qwds, question) and ('INSTRUMENT' in types):
            question_type = 'ins_type_have'
            question_types.append(question_type)

        # 单元维护保养手段
        if self.method_words(self.method_qwds, question) and ('UNIT' in types):
            question_type = 'unit_method'
            question_types.append(question_type)

        # 单元有哪些子部件
        if self.method_words(self.have_qwds, question) and ('UNIT' in types):
            question_type = 'unit_have'
            question_types.append(question_type)

        # 某子部件属于哪个单元
        if self.method_words(self.belong_qwds, question) and ('SUB_UNIT' in types):
            question_type = 'sub_unit_belong'
            question_types.append(question_type)

        # 某保养手段可以用在哪些单元
        if self.method_words(self.apply_qwds, question) and ('METHOD' in types):
            question_type = 'method_apply'
            question_types.append(question_type)

        # 遇到某情况怎么解决
        if self.method_words(self.method_qwds, question) and ('APPARANCE' in types):
            question_type = '暂未构造'
            question_types.append(question_type)

        # 哪些单元会出现某种故障
        if self.method_words(self.appear_on, question) and ('APPARANCE' in types):
            question_type = 'appear_on'
            question_types.append(question_type)

        # 将多个分类结果进行合并处理，组装成一个字典
        data['question_types'] = question_types

        return data


if __name__ == '__main__':
    handler = QuestionClassifier()
    while 1:
        question = input('input an question:')
        # question = 'A2000有哪些单元组成'
        data = handler.classify(question)
        print(data)
